package com.xinlan.imageeditlibrary.editimage.utils;


import android.graphics.Point;
import android.util.FloatMath;

import java.util.Random;

/**
 * User: JJ
 * Date: 13-4-10
 * Time: 下午6:32
 */
public class MathUtils {

    private static final String TAG = "MathUtils";

    public static Random RANDOM = new Random(System.nanoTime());

    public static final float PI = (float) Math.PI;

    public static final float DEG_TO_RAD = PI / 180.0f;
    public static final float RAD_TO_DEG = 180.0f / PI;


    public static float getScaleValueFittingScreen(float screenWidth, float screenHeight, float bmpWidth, float bmpHeight, boolean isFitXY) {
        float scaleValue = 1.0f;

        if (isFitXY) {
            if (bmpWidth * screenHeight > bmpHeight * screenWidth) {// 适应宽度
                scaleValue = screenHeight / bmpHeight;
            } else { // 适应高度
                scaleValue = screenWidth / bmpWidth;
            }
        } else {
            if (bmpWidth * screenHeight > bmpHeight * screenWidth) {// 适应宽度
                scaleValue = screenWidth / bmpWidth;
            } else { // 适应高度
                scaleValue = screenHeight / bmpHeight;
            }
        }

        return scaleValue;
    }

    public static final float random(final float pMin, final float pMax) {
        return pMin + RANDOM.nextFloat() * (pMax - pMin);
    }

    public static final boolean isPowerOfTwo(final int n) {
        return ((n != 0) && (n & (n - 1)) == 0);
    }

    public static final int nextPowerOfTwo(final int n) {
        int k = n;

        if (k == 0) {
            return 1;
        }

        k--;

        for (int i = 1; i < 32; i <<= 1) {
            k = k | k >> i;
        }

        return k + 1;
    }

    public static final int sum(final int[] pValues) {
        int sum = 0;
        for (int i = pValues.length - 1; i >= 0; i--) {
            sum += pValues[i];
        }

        return sum;
    }

    public float distance(final float pX1, final float pY1, final float pX2, final float pY2) {
        final float dX = pX2 - pX1;
        final float dY = pY2 - pY1;
        return FloatMath.sqrt((dX * dX) + (dY * dY));
    }

    public float computeDegree(final Point p1, final Point p2) {
        float tran_x = p1.x - p2.x;
        float tran_y = p1.y - p2.y;
        float degree = 0.0f;
        float angle = (float) (Math.asin(tran_x / Math.sqrt(tran_x * tran_x + tran_y * tran_y)) * 180 / Math.PI);
        if (!Float.isNaN(angle)) {
            if (tran_x >= 0 && tran_y <= 0) {// 第一象限
                degree = angle;
            } else if (tran_x <= 0 && tran_y <= 0) {// 第二象限
                degree = angle;
            } else if (tran_x <= 0 && tran_y >= 0) {// 第三象限
                degree = -180 - angle;
            } else if (tran_x >= 0 && tran_y >= 0) {// 第四象限
                degree = 180 - angle;
            }
        }
        return degree;
    }

    private static boolean isPointUpLine(final int x1, final int y1, final int x2, final int y2, final int x, final int y) {
        float n = 0;
        if (x1 == x2) {
            if (x > x1) {
                return false;
            } else {
                return true;
            }
        } else {
            n = y1 - (x1 - x) * (y1 - y2) / (x1 - x2);
            if (n > y) {
                return true;
            } else {
                return false;
            }
        }
    }

    public static boolean isInIrregularRect(final Point p1, final Point p2, final Point p3, final Point p4, final Point p) {
        boolean isInRect = false;

        if ((isPointUpLine(p1.x, p1.y, p2.x, p2.y, p.x, p.y) ^ (isPointUpLine(
                p3.x, p3.y, p4.x, p4.y, p.x, p.y)))
                && (isPointUpLine(p2.x, p2.y, p3.x, p3.y, p.x, p.y) ^ (isPointUpLine(
                p3.x, p3.y, p1.x, p1.y, p.x, p.y)))) {

        }

        return isInRect;
    }

    public static int bringToBounds(final int pMinValue, final int pMaxValue, final int pValue) {
        return Math.max(pMinValue, Math.min(pMaxValue, pValue));
    }

    public static float bringToBounds(final float pMinValue, final float pMaxValue, final float pValue) {
        return Math.max(pMinValue, Math.min(pMaxValue, pValue));
    }

    public static float[] rotateAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY) {
        if (pRotation != 0) {
            final float rotationRad = MathUtils.degToRad(pRotation);
            final float sinRotationRad = FloatMath.sin(rotationRad);
            final float cosRotationInRad = FloatMath.cos(rotationRad);

            for (int i = pVertices.length - 2; i >= 0; i -= 2) {
                final float pX = pVertices[i];
                final float pY = pVertices[i + 1];
                pVertices[i] = pRotationCenterX + (cosRotationInRad * (pX - pRotationCenterX) - sinRotationRad * (pY - pRotationCenterY));
                pVertices[i + 1] = pRotationCenterY + (sinRotationRad * (pX - pRotationCenterX) + cosRotationInRad * (pY - pRotationCenterY));
            }
        }
        return pVertices;
    }

    public static float[] scaleAroundCenter(final float[] pVertices, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
        if (pScaleX != 1 || pScaleY != 1) {
            for (int i = pVertices.length - 2; i >= 0; i -= 2) {
                pVertices[i] = pScaleCenterX + (pVertices[i] - pScaleCenterX) * pScaleX;
                pVertices[i + 1] = pScaleCenterY + (pVertices[i + 1] - pScaleCenterY) * pScaleY;
            }
        }

        return pVertices;
    }

    public static float[] rotateAndScaleAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
        MathUtils.rotateAroundCenter(pVertices, pRotation, pRotationCenterX, pRotationCenterY);
        return MathUtils.scaleAroundCenter(pVertices, pScaleX, pScaleY, pScaleCenterX, pScaleCenterY);
    }

    public static float[] revertScaleAroundCenter(final float[] pVertices, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
        return MathUtils.scaleAroundCenter(pVertices, 1 / pScaleX, 1 / pScaleY, pScaleCenterX, pScaleCenterY);
    }

    public static float[] revertRotateAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY) {
        return MathUtils.rotateAroundCenter(pVertices, -pRotation, pRotationCenterX, pRotationCenterY);
    }

    public static float[] revertRotateAndScaleAroundCenter(final float[] pVertices, final float pRotation, final float pRotationCenterX, final float pRotationCenterY, final float pScaleX, final float pScaleY, final float pScaleCenterX, final float pScaleCenterY) {
        MathUtils.revertScaleAroundCenter(pVertices, pScaleX, pScaleY, pScaleCenterX, pScaleCenterY);
        return MathUtils.revertRotateAroundCenter(pVertices, pRotation, pRotationCenterX, pRotationCenterY);
    }

    public static final float radToDeg(final float pRad) {
        return RAD_TO_DEG * pRad;
    }

    public static final float degToRad(final float pDegree) {
        return DEG_TO_RAD * pDegree;
    }

}
